#include "gobang.h"
#include <QMessageBox>
#include <QPushButton>

Gobang::Gobang(QWidget *parent)
    : QWidget(parent), playerTurn(true), gameOver(false)
{
    setFixedSize(600, 660);
    QPushButton *pPB = new QPushButton(this);
    pPB->setText("Reset");
    pPB->setFixedSize(200, 40);
    pPB->move(200, 600);
    connect(pPB, &QPushButton::clicked, [this]()
            { resetGame(); });
    resetGame();
}

Gobang::~Gobang()
{
}

void Gobang::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    drawBoard(painter);
    drawPieces(painter);
}

void Gobang::drawBoard(QPainter &painter)
{
    painter.setPen(Qt::black);
    for (int i = 0; i < 15; ++i)
    {
        painter.drawLine(20, 20 + i * 40, 580, 20 + i * 40);
        painter.drawLine(20 + i * 40, 20, 20 + i * 40, 580);
    }
}

void Gobang::drawPieces(QPainter &painter)
{
    for (int i = 0; i < 15; ++i)
    {
        for (int j = 0; j < 15; ++j)
        {
            if (board[i][j] == 1)
            {
                painter.setBrush(Qt::black);
                painter.drawEllipse(QPoint(20 + i * 40, 20 + j * 40), 18, 18);
            }
            else if (board[i][j] == 2)
            {
                painter.setBrush(Qt::white);
                painter.drawEllipse(QPoint(20 + i * 40, 20 + j * 40), 18, 18);
            }
        }
    }
}

void Gobang::mousePressEvent(QMouseEvent *event)
{
    if (gameOver)
    {
        return;
    }

    int x = event->x();
    int y = event->y();

    if (x < 20 || x > 580 || y < 20 || y > 580)
    {
        return;
    }

    int i = (x - 10) / 40;
    int j = (y - 10) / 40;

    if (board[i][j] != 0)
    {
        return;
    }

    if (playerTurn)
    {
        board[i][j] = 1;
        update();
        if (checkWin(i, j))
        {
            QMessageBox::information(this, "Game Over", "You Win!");
            gameOver = true;
            return;
        }
        playerTurn = false;
        aiMove();
    }
}

void Gobang::aiMove()
{
    int bestScore = INT_MIN;
    QPoint bestMove(-1, -1);

    QVector<QPoint> moves = generateMoves();
    for (auto &move : moves)
    {
        // 模拟AI落子
        board[move.x()][move.y()] = 2;
        int score = minimax(MAX_DEPTH - 1, INT_MIN, INT_MAX, false);
        board[move.x()][move.y()] = 0; // 撤销落子

        if (score > bestScore)
        {
            bestScore = score;
            bestMove = move;
        }
    }

    if (bestMove.x() != -1)
    {
        board[bestMove.x()][bestMove.y()] = 2;
        if (checkWin(bestMove.x(), bestMove.y()))
        {
            QMessageBox::information(this, "Game Over", "AI Wins!");
            gameOver = true;
            return;
        }
        lastMove = bestMove;
        playerTurn = true;
        update();
    }
}

int Gobang::evaluatePosition(int x, int y)
{
    int score = 0;

    // 检查四个方向（水平、垂直、对角线）
    int directions[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};
    for (int d = 0; d < 4; ++d)
    {
        int dx = directions[d][0];
        int dy = directions[d][1];

        // 检查AI的连子情况
        int aiCount = countConsecutive(x, y, dx, dy, 2);
        if (aiCount >= 4)
        {
            score += 1000; // 直接形成五连
        }
        else if (aiCount == 3)
        {
            score += 100; // 形成四连
        }
        else if (aiCount == 2)
        {
            score += 10; // 形成三连
        }

        // 检查玩家的连子情况
        int playerCount = countConsecutive(x, y, dx, dy, 1);
        if (playerCount >= 4)
        {
            score += 500; // 必须阻止玩家形成五连
        }
        else if (playerCount == 3)
        {
            score += 50; // 阻止玩家形成四连
        }
        else if (playerCount == 2)
        {
            score += 5; // 阻止玩家形成三连
        }
    }

    return score;
}

int Gobang::countConsecutive(int x, int y, int dx, int dy, int player)
{
    int count = 0;

    // 向一个方向搜索
    for (int i = 1; i < 5; ++i)
    {
        int nx = x + dx * i;
        int ny = y + dy * i;
        if (nx >= 0 && nx < 15 && ny >= 0 && ny < 15 && board[nx][ny] == player)
        {
            count++;
        }
        else
        {
            break;
        }
    }

    // 向相反方向搜索
    for (int i = 1; i < 5; ++i)
    {
        int nx = x - dx * i;
        int ny = y - dy * i;
        if (nx >= 0 && nx < 15 && ny >= 0 && ny < 15 && board[nx][ny] == player)
        {
            count++;
        }
        else
        {
            break;
        }
    }

    return count;
}

bool Gobang::checkWin(int x, int y)
{
    int directions[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};
    for (int d = 0; d < 4; ++d)
    {
        int count = 1;
        for (int i = 1; i < 5; ++i)
        {
            int nx = x + directions[d][0] * i;
            int ny = y + directions[d][1] * i;
            if (nx >= 0 && nx < 15 && ny >= 0 && ny < 15 && board[nx][ny] == board[x][y])
            {
                count++;
            }
            else
            {
                break;
            }
        }
        for (int i = 1; i < 5; ++i)
        {
            int nx = x - directions[d][0] * i;
            int ny = y - directions[d][1] * i;
            if (nx >= 0 && nx < 15 && ny >= 0 && ny < 15 && board[nx][ny] == board[x][y])
            {
                count++;
            }
            else
            {
                break;
            }
        }
        if (count >= 5)
        {
            return true;
        }
    }
    return false;
}

void Gobang::resetGame()
{
    for (int i = 0; i < 15; ++i)
    {
        for (int j = 0; j < 15; ++j)
        {
            board[i][j] = 0;
        }
    }
    playerTurn = true;
    gameOver = false;
    update();
}

int Gobang::evaluateBoard()
{
    int score = 0;

    // 遍历所有方向
    int directions[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};

    for (int i = 0; i < 15; ++i)
    {
        for (int j = 0; j < 15; ++j)
        {
            if (board[i][j] == 0)
                continue;

            // 对每个棋子评估四个方向
            for (auto &dir : directions)
            {
                int dx = dir[0], dy = dir[1];
                int count = 1;
                bool blocked = false;

                // 正向搜索
                for (int k = 1; k < 5; ++k)
                {
                    int x = i + dx * k;
                    int y = j + dy * k;
                    if (x < 0 || x >= 15 || y < 0 || y >= 15)
                    {
                        blocked = true;
                        break;
                    }
                    if (board[x][y] != board[i][j])
                    {
                        if (board[x][y] != 0)
                            blocked = true;
                        break;
                    }
                    count++;
                }

                // 反向搜索
                for (int k = 1; k < 5; ++k)
                {
                    int x = i - dx * k;
                    int y = j - dy * k;
                    if (x < 0 || x >= 15 || y < 0 || y >= 15)
                    {
                        blocked = true;
                        break;
                    }
                    if (board[x][y] != board[i][j])
                    {
                        if (board[x][y] != 0)
                            blocked = true;
                        break;
                    }
                    count++;
                }

                // 根据连子数计算得分
                int value = 0;
                if (count >= 5)
                {
                    value = 100000; // 五连直接胜利
                }
                else
                {
                    switch (count)
                    {
                    case 4:
                        value = blocked ? 1000 : 10000;
                        break; // 四连
                    case 3:
                        value = blocked ? 100 : 1000;
                        break; // 三连
                    case 2:
                        value = blocked ? 10 : 100;
                        break; // 二连
                    }
                }

                // AI得分增加，玩家得分减少
                score += (board[i][j] == 2) ? value : -value;
            }
        }
    }
    return score;
}

int Gobang::minimax(int depth, int alpha, int beta, bool maximizingPlayer)
{
    // 终止条件：达到最大深度或游戏结束
    if (depth == 0 || checkWin(lastMove.x(), lastMove.y()))
    {
        return evaluateBoard();
    }

    // 生成可能的落子位置
    QVector<QPoint> moves = generateMoves();

    if (maximizingPlayer)
    {
        int maxEval = INT_MIN;
        for (auto &move : moves)
        {
            // 模拟AI落子
            board[move.x()][move.y()] = 2;
            int eval = minimax(depth - 1, alpha, beta, false);
            board[move.x()][move.y()] = 0; // 撤销落子

            maxEval = std::max(maxEval, eval);
            alpha = std::max(alpha, eval);
            if (beta <= alpha)
                break; // Alpha-Beta剪枝
        }
        return maxEval;
    }
    else
    {
        int minEval = INT_MAX;
        for (auto &move : moves)
        {
            // 模拟玩家落子
            board[move.x()][move.y()] = 1;
            int eval = minimax(depth - 1, alpha, beta, true);
            board[move.x()][move.y()] = 0; // 撤销落子

            minEval = std::min(minEval, eval);
            beta = std::min(beta, eval);
            if (beta <= alpha)
                break; // Alpha-Beta剪枝
        }
        return minEval;
    }
}

QVector<QPoint> Gobang::generateMoves()
{
    QVector<QPoint> moves;
    // 只搜索周围有棋子的位置（启发式搜索）
    for (int i = 0; i < 15; ++i)
    {
        for (int j = 0; j < 15; ++j)
        {
            if (board[i][j] == 0 && hasNeighbor(i, j))
            {
                moves.append(QPoint(i, j));
            }
        }
    }
    return moves;
}

bool Gobang::hasNeighbor(int x, int y)
{
    // 检查周围2格内是否有棋子
    for (int i = -2; i <= 2; ++i)
    {
        for (int j = -2; j <= 2; ++j)
        {
            int nx = x + i, ny = y + j;
            if (nx >= 0 && nx < 15 && ny >= 0 && ny < 15)
            {
                if (board[nx][ny] != 0)
                    return true;
            }
        }
    }
    return false;
}
